use std::{
    ops::{Deref, DerefMut},
    ptr::NonNull,
};

use common_base::prelude::*;

use super::dataset::{Dataset, DatasetType};

/// DatasetOwner is allocate on Heap, and can not move.

#[derive(Debug, Clone)]
pub struct DatasetOwner(std::pin::Pin<Box<Dataset>>);

impl Deref for DatasetOwner {
    type Target = std::pin::Pin<Box<Dataset>>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for DatasetOwner {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl From<Dataset> for DatasetOwner {
    fn from(v: Dataset) -> Self {
        let mut owner = DatasetOwner(Box::pin(v));
        let owner_ref = (&owner).into();
        owner.set_self_ref(owner_ref);
        owner
    }
}

impl DatasetOwner {
    pub fn get_instance(table_name: &str, dataset_type: DatasetType) -> DatasetOwner {
        Dataset::get_instance(table_name, dataset_type).into()
    }

    pub fn deserizlize_from_json(dataset_json: serde_json::Value) -> Result<Self> {
        Dataset::deserizlize_from_json(dataset_json).and_then(|v| Ok(DatasetOwner::from(v)))
    }
}

/// DatasetRef is a raw pointer, which point to DatasetOwner

#[derive(Debug, Clone, Copy)]
pub struct DatasetRef(std::ptr::NonNull<DatasetOwner>);

impl From<&DatasetOwner> for DatasetRef {
    fn from(v: &DatasetOwner) -> Self {
        DatasetRef(NonNull::from(v))
    }
}
impl From<&mut DatasetOwner> for DatasetRef {
    fn from(v: &mut DatasetOwner) -> Self {
        DatasetRef(NonNull::from(v))
    }
}

impl DatasetRef {
    pub fn to_owner_ref(&self) -> &DatasetOwner {
        unsafe { self.0.as_ref() }
    }
    pub fn to_owner_mut(&mut self) -> &mut DatasetOwner {
        unsafe { self.0.as_mut() }
    }
}
